package sale_admin

import (
	"context"
	"encoding/json"
	"errors"
	"strconv"
	"strings"
	"time"

	"sale-admin/config/mysql"
	"sale-admin/internal/app/grpc/client"
	"sale-admin/internal/app/grpc/protoc/devicec"
	"sale-admin/internal/app/grpc/protoc/sale_adminc"
	"sale-admin/internal/app/web/schema"
	"sale-admin/internal/app/web/service"
	"sale-admin/internal/app/web/service/common"
	"sale-admin/internal/app/web/service/coupon"
	"sale-admin/internal/app/web/service/redemption"
	"sale-admin/internal/app/web/service/robot"
	"sale-admin/internal/app/web/service/statistics"
	"sale-admin/internal/dal"
	"sale-admin/internal/dao"
	"sale-admin/internal/define"
	"sale-admin/internal/models"
	"sale-admin/internal/pkg/points"

	"192.168.1.75/go-pkg/helper"
	"192.168.1.75/go-pkg/logx"
	"github.com/golang-module/carbon/v2"
	"github.com/samber/lo"
	"github.com/shopspring/decimal"
	"gorm.io/gorm"
)

type SaleAdminService struct {
	sale_adminc.UnimplementedSaleAdminServiceServer
}

// 新增编辑机器信息
func (s *SaleAdminService) SaveRobotInfo(context context.Context, req *sale_adminc.RobotInfoReq) (*sale_adminc.RobotInfoRsp, error) {
	rsp := &sale_adminc.RobotInfoRsp{}
	db := mysql.NewDB()

	oldRobotRecord, _ := dao.Robot{}.RobotDetail(context, db, "", req.RobotId, "")
	if oldRobotRecord == nil || oldRobotRecord.ID == "" { // 新增
		var InsertData models.MaRobot
		InsertData.ID = req.MerchantId
		InsertData.MerchantID = req.MerchantId
		InsertData.SalesID = req.IdentificationCode
		InsertData.RobotType = strconv.Itoa(int(req.DeviceType))
		InsertData.RobotName = req.RobotId
		InsertData.Areas1, _ = strconv.Atoi(req.ProvinceId)
		InsertData.Areas2, _ = strconv.Atoi(req.CityId)
		InsertData.Areas3, _ = strconv.Atoi(req.LocationId)
		InsertData.Areas5, _ = strconv.Atoi(req.DistrictId)
		InsertData.AddTime = time.Now()
		InsertData.MerchantChangedAt = time.Now().Unix()
		err := db.Model(&models.MaRobot{}).Create(&InsertData).Error
		if err != nil {
			rsp.Code = -1
			rsp.Msg = "新增机器失败"
		}
	} else { // 编辑
		UpdateData := make(map[string]interface{})
		UpdateData["id"] = req.MerchantId
		UpdateData["merchant_id"] = req.MerchantId
		if oldRobotRecord.MerchantID != req.MerchantId {
			UpdateData["merchant_changed_at"] = time.Now().Unix()
		}
		UpdateData["sales_id"] = req.IdentificationCode
		UpdateData["robot_type"] = strconv.Itoa(int(req.DeviceType))
		UpdateData["payment_type1"] = 0
		UpdateData["payment_type2"] = 0
		UpdateData["payment_type3"] = 0
		UpdateData["payment_type4"] = 0
		UpdateData["payment1"] = 0
		UpdateData["payment2"] = 0
		UpdateData["payment3"] = 0
		UpdateData["payment4"] = 0
		err := db.Model(&models.MaRobot{}).
			Where("robot_name = ?", req.RobotId).
			Updates(&UpdateData).Error
		if err != nil {
			rsp.Code = -1
			rsp.Msg = "编辑机器失败"
		}

		// 机器的商户id，省市区商场 配置如果与GRPC获取不同，则执行更新
		myAreas1, _ := strconv.Atoi(req.ProvinceId)
		myAreas2, _ := strconv.Atoi(req.CityId)
		myAreas3, _ := strconv.Atoi(req.LocationId)
		myAreas5, _ := strconv.Atoi(req.DistrictId)
		if oldRobotRecord.Areas1 != myAreas1 || oldRobotRecord.Areas2 != myAreas2 ||
			oldRobotRecord.Areas3 != myAreas3 || oldRobotRecord.Areas5 != myAreas5 {
			var UpdateData models.MaRobot
			UpdateData.Areas1 = myAreas1
			UpdateData.Areas2 = myAreas2
			UpdateData.Areas3 = myAreas3
			UpdateData.Areas5 = myAreas5
			err := db.Model(&models.MaRobot{}).
				Where("robot_name = ?", req.RobotId).
				Select("areas1", "areas2", "areas3", "areas5").
				Updates(&UpdateData).Error
			if err != nil {
				rsp.Code = -1
				rsp.Msg = "编辑机器失败"
			}
		}
	}
	return rsp, nil
}

// 获取热力图所需订单数据
func (s *SaleAdminService) GetHeatMapInfo(
	context context.Context,
	req *sale_adminc.RobotHeatMapReq, // GRPC请求信息。包括机器唯一识别码，开始时间，结束时间
) (
	*sale_adminc.RobotHeatMapListRsp, // GRPC返回的数据
	error,
) {
	rsp := &sale_adminc.RobotHeatMapRsp{}
	rspList := &sale_adminc.RobotHeatMapListRsp{}
	db := mysql.NewDB()
	// 获取筛查的数据
	mydata, count, _ := statistics.OrderStatisticService{}.GetHeatMapInfo(context, db, req.StartTime, req.EndTime, req.IdentificationCode, 0, 0)
	rspList.List = []*sale_adminc.RobotHeatMapRsp{}
	for _, v := range mydata {
		rsp.OrderCount = int64(v.MyOrderCount)
		rsp.Gmv = float32(v.Gmv)
		rsp.PaymentAmount = float32(v.MyPaymentAmount)
		rsp.RefundOrderCount = int64(v.MyRefundOrderCount)
		rsp.RefundOrderAmount = float32(v.MyRefundOrderAmount)
		rsp.StartOrderCount = int64(v.MyStartOrderCount)
		rsp.SuccessOrderCount = int64(v.MySuccessOrderCount)
		rsp.FailedOrderCount = int64(v.MyFailedOrderCount)
		rsp.NotPayOrderCount = int64(v.MyNotPayOrderCount)
		rsp.PayNum = int64(v.PayNum)
		rsp.FaceCount = int64(v.FaceCount)
		rsp.FaceCount0 = int64(v.FaceCount0)
		rsp.FaceCount1 = int64(v.FaceCount1)
		rsp.FaceCount2 = int64(v.FaceCount2)
		rsp.FaceCount3 = int64(v.FaceCount3)
		rsp.ClickNum = int64(v.ClickNum)
		// GRP List格式。多组
		rspList.List = append(rspList.List, rsp)
	}
	rspList.Code = 0
	rspList.Msg = "获取成功"
	rspList.Total = count
	return rspList, nil
}

// GetCouponCode 获取优惠券码
func (s SaleAdminService) CreateRedemptionCode(
	ctx context.Context,
	req *sale_adminc.RedemptionCodeReq,
) (rsp *sale_adminc.RedemptionCodeRsp, err error) {
	db := mysql.NewDB()
	var codeList []string
	rsp = &sale_adminc.RedemptionCodeRsp{}
	// 旧版本的兑换码生成
	if req.CouponBatchId == "" {
		codeList, err = redemption.RedemptionService{}.Add(ctx, db, req.MerchantId, int(req.Num), req.Value, req.ExpirationTime, "")
	} else {
		expiredAt := carbon.Parse(req.ExpirationTime).ToStdTime().Unix()
		codeList, err = coupon.CouponCode{}.GetCode(ctx, req.MerchantId, req.CouponBatchId, int(req.Num), expiredAt, req.OutTradeNo)
	}
	if err != nil {
		rsp.Code = -1
		rsp.Msg = err.Error()
		return rsp, nil
	} else {
		rsp.Code = 0
		rsp.RedemptionCode = codeList
		return rsp, nil
	}
}

// CouponCodeStatus 兑换码使用状态
func (s SaleAdminService) RedemptionCodeStatus(
	ctx context.Context,
	req *sale_adminc.RedemptionCodeStatusReq,
) (*sale_adminc.RedemptionCodeStatusRsp, error) {
	status, err := redemption.RedemptionService{}.Status(ctx, mysql.NewDB(), req.MerchantId, req.RedemptionCode)
	rsp := &sale_adminc.RedemptionCodeStatusRsp{}
	if err != nil {
		rsp.Code = -1
		rsp.Msg = err.Error()
		rsp.Status = 0
		return rsp, nil
	} else {
		rsp.Code = 0
		rsp.Msg = ""
		rsp.Status = int64(status)
		return rsp, nil
	}
}

// CouponUseRecord 兑换码使用记录
func (s SaleAdminService) RedemptionUsageLog(
	ctx context.Context,
	req *sale_adminc.RedemptionUsageLogReq,
) (*sale_adminc.RedemptionUsageLogRsp, error) {
	log, err := redemption.RedemptionService{}.UsageLog(
		ctx,
		mysql.NewDB(),
		req.MerchantId,
		req.RedemptionCode,
		int(req.StartTime),
		int(req.EndTime),
		int(req.Page),
		int(req.Limit),
	)
	rsp := &sale_adminc.RedemptionUsageLogRsp{}
	if err != nil {
		rsp.Code = -1
		rsp.Msg = err.Error()
		rsp.List = nil
		return rsp, nil
	} else {
		for _, r := range log {
			rsp.List = append(rsp.List, &sale_adminc.RedemptionUsageLogRsp_UsageLog{
				GoodsId:   r.GoodsID,
				GoodsName: r.GoodsName,
				UsedAt:    r.UsedAt,
			})
		}
		rsp.Code = 0
		return rsp, nil
	}
}

// PortraitsAnalysis 用户画像
func (s SaleAdminService) PortraitsAnalysis(ctx context.Context, req *sale_adminc.PortraitsAnalysisReq) (*sale_adminc.PortraitsAnalysisRsp, error) {
	db := mysql.NewDB()
	rsp := &sale_adminc.PortraitsAnalysisRsp{}
	rsp.Data = &sale_adminc.PortraitsAnalysisRsp_Data{}
	merchantIDs, err1 := common.Order{}.GetMerchantChildren(ctx, req.MerchantId, []string{})
	if err1 != nil {
		rsp.Code = -1
		rsp.Msg = "获取商户错误"
		return rsp, nil
	}
	robotList, _, _ := dao.Robot{}.RobotList(ctx, db, strings.Join(merchantIDs, ","), "", "", req.RobotIds, "", "", "", "")
	SalesIDList := []string{}
	for _, v := range robotList {
		SalesIDList = append(SalesIDList, v.SalesID)
	}
	salesID := strings.Join(SalesIDList, ",")
	startTime := carbon.CreateFromTimestamp(req.StartTime).ToDateTimeString()
	endTime := carbon.CreateFromTimestamp(req.EndTime).ToDateTimeString()
	data, err := statistics.DrawService{}.Draw(ctx, db, "", "",
		0, salesID, []string{}, 1, startTime, endTime, "", "", "", 0, 0)
	data1 := data.([]struct {
		Age   int `json:"age"`
		Sex0  int `json:"sex0"`
		Sex1  int `json:"sex1"`
		Sex_1 int `json:"sex-1"`
	})
	list := []*sale_adminc.PortraitsAnalysisRsp_List{}
	for _, v := range data1 {
		item := &sale_adminc.PortraitsAnalysisRsp_List{}
		item.Age = int64(v.Age)
		item.Sex0 = int64(v.Sex0)  // 女
		item.Sex1 = int64(v.Sex1)  // 男
		item.Sex2 = int64(v.Sex_1) // 未知
		list = append(list, item)
	}
	if err != nil {
		rsp.Code = -1
		rsp.Msg = err.Error()
		return rsp, nil
	} else {
		rsp.Code = 0
		rsp.Data.List = list
		return rsp, nil
	}
}

// GoodsList 商品列表
func (s SaleAdminService) GoodsList(ctx context.Context, req *sale_adminc.GoodsListReq) (*sale_adminc.GoodsListRsp, error) {
	res := &sale_adminc.GoodsListRsp{}
	res.Data = &sale_adminc.GoodsListRsp_Data{}
	db := mysql.NewDB()
	var goodsList = []models.MaGoodsInfo{}
	db.Model(&models.MaGoodsInfo{}).
		Where("merchant_id = ?", req.MerchantId).
		Where("deleted = 0").
		Find(&goodsList)
	for _, v := range goodsList {
		item := &sale_adminc.GoodsListRsp_List{
			GoodsId:          v.GoodsID,
			GoodsName:        v.GoodsName1,
			Price:            float32(v.Price),
			GoodsDescription: v.GoodsDescription1,
			GoodsImage:       v.GoodsImage,
			GoodsStatus:      int32(v.GoodsStatus),
			TotalSales:       int64(v.TotalSales),
			GoodsCode:        v.GoodsCode,
			UseRc:            int32(v.UseRC),
			CodeImage:        v.CodeImage,
			IsAuth:           int32(v.IsAuth),
			UnderlinePrice:   float32(v.Price1),
			GoodsDetail:      v.GoodsDetail,
			GoodsVoice:       v.GoodsVoice,
			ShowTag:          v.ShowTag,
			GoodsType:        int32(v.GoodsType),
			Points:           float32(v.Points),
			PointsSupport:    int32(v.PointsSupport),
		}
		res.Data.List = append(res.Data.List, item)
	}
	return res, nil
}

// GoodsStock 商品库存
func (s SaleAdminService) GoodsStock(ctx context.Context, req *sale_adminc.GoodsStockReq) (*sale_adminc.GoodsStockRsp, error) {
	db := mysql.NewDB()
	res := &sale_adminc.GoodsStockRsp{}
	// 获取salesID
	robotIDs := []string{}
	salesIDs := []string{}
	if req.RobotId != "" {
		robotIDs = strings.Split(req.RobotId, ",")
	}
	for _, robotID := range robotIDs {
		RobotInfo, _ := dao.Robot{}.RobotDetail(ctx, db, req.MerchantId, robotID, "")
		if RobotInfo == nil || RobotInfo.ID == "" {
			continue
		}
		salesIDs = append(salesIDs, RobotInfo.SalesID)
	}

	// 机器货物信息
	SalesInfoList := []models.MaRobotSalesInfo{}
	tx := db.Model(&models.MaRobotSalesInfo{})
	// 如果salesIDs为空，则获取该商户的全部设备
	if len(salesIDs) <= 0 {
		cli, err := client.GetDeviceAdminClient()
		if err != nil {
			return res, nil
		}
		rsp, err := cli.DeviceList(ctx, &devicec.DeviceListReq{
			MerchantId: req.MerchantId,
		})
		if err != nil || rsp == nil {
			return res, nil
		}
		for _, record := range rsp.List {
			salesIDs = append(salesIDs, record.IdentificationCode)
		}
	}
	// 获取售卖信息
	tx.Where("sales_id IN ?", salesIDs).
		Where("container_status = 1").
		Where("container_use_status = 1").
		Find(&SalesInfoList)
	GoodsStockMap := make(map[string]int)
	GoodsIDList := []string{}
	for _, v := range SalesInfoList {
		GoodsStockMap[v.GoodsID] += v.GoodsInventory
		if !lo.Contains(GoodsIDList, v.GoodsID) {
			GoodsIDList = append(GoodsIDList, v.GoodsID)
		}
	}
	// 商品名称信息
	GoodsList := []models.MaGoodsInfo{}
	db.Model(&models.MaGoodsInfo{}).
		Where("goods_id in (?)", GoodsIDList).
		Select("goods_id,goods_name1").
		Find(&GoodsList)
	GoodsIDNameMap := make(map[string]string)
	for _, v := range GoodsList {
		GoodsIDNameMap[v.GoodsID] = v.GoodsName1
	}
	list := []*sale_adminc.GoodsStockRsp_List{}
	for k, v := range GoodsStockMap {
		item := &sale_adminc.GoodsStockRsp_List{}
		item.GoodsId = k
		if _, ok := GoodsIDNameMap[k]; ok {
			item.GoodsName = GoodsIDNameMap[k]
		}
		item.Stock = int64(v)
		list = append(list, item)
	}
	res.Code = 0
	res.Msg = ""
	res.Data = list
	return res, nil
}

// SaleCount 出货量统计
func (s SaleAdminService) SaleCount(ctx context.Context, req *sale_adminc.SaleCountReq) (*sale_adminc.SaleCountRsp, error) {
	db := mysql.NewDB()
	res := &sale_adminc.SaleCountRsp{}

	// 机器信息
	RobotInfo, _ := dao.Robot{}.RobotDetail(ctx, db, req.MerchantId, req.RobotId, "")
	if RobotInfo == nil || RobotInfo.ID == "" {
		res.Code = -1
		res.Msg = "机器信息不存在"
		return res, nil
	}

	// 订单表 状态为订单已完结 出货成功 : end = 1 and order_status = 4
	CountDataList := []string{}
	db.Model(&models.MaOrder{}).
		Where("robot_name = ?", req.RobotId).
		Where("merchant_id = ?", req.MerchantId).
		Where("created_at between ? and ?", req.StartTime, req.EndTime).
		Where("end = 1 and order_status = 4").
		Pluck("count_data", &CountDataList)
	list := []*sale_adminc.SaleCountRsp_List{}
	if len(CountDataList) == 0 {
		res.Code = 0
		res.Msg = ""
		res.Data = list
		return res, nil
	}
	GoodsIDCount := make(map[string]int64)
	GoodsIDList := []string{}
	for _, countData := range CountDataList {
		GoodsList := []schema.OrderGoodsDetailOld{}
		json.Unmarshal([]byte(countData), &GoodsList)
		for _, v := range GoodsList {
			GoodsIDCount[v.GoodsID] += 1
			GoodsIDList = append(GoodsIDList, v.GoodsID)
		}
	}

	// 商品名称信息
	GoodsList := []models.MaGoodsInfo{}
	db.Model(&models.MaGoodsInfo{}).
		Where("goods_id in (?)", GoodsIDList).
		Select("goods_id,goods_name1").
		Find(&GoodsList)
	GoodsIDNameMap := make(map[string]string)
	for _, v := range GoodsList {
		GoodsIDNameMap[v.GoodsID] = v.GoodsName1
	}

	for goodsID, count := range GoodsIDCount {
		list = append(list, &sale_adminc.SaleCountRsp_List{
			GoodsId:   goodsID,
			GoodsName: GoodsIDNameMap[goodsID],
			Count:     count,
		})
	}
	res.Code = 0
	res.Msg = ""
	res.Data = list
	return res, nil
}

// OrderList 订单列表
func (s SaleAdminService) OrderList(ctx context.Context, req *sale_adminc.OrderListReq) (*sale_adminc.OrderListRsp, error) {
	res := &sale_adminc.OrderListRsp{}
	res.Data = &sale_adminc.OrderListRsp_Data{}

	db := mysql.NewDB()
	tx := db.Model(&models.MaOrder{}).
		Where("merchant_id = ?", req.MerchantId)
	if req.RobotIds != "" {
		tx.Where("robot_name in (?)", strings.Split(req.RobotIds, ","))
	}
	if req.StartTime != 0 && req.EndTime != 0 {
		tx.Where("created_at between ? and ?", req.StartTime, req.EndTime)
	}
	if req.OrderStatus != 0 {
		tx.Where("order_status = ?", req.OrderStatus)
	}
	tx.Count(&res.Data.Count)

	var list = []models.MaOrder{}
	helper.Gorm{}.Paginate(tx, int(req.Page), int(req.Limit)).Find(&list)
	for _, v := range list {
		item := &sale_adminc.OrderListRsp_List{}
		item.OrderId = v.OrderID
		item.MerchantId = v.MerchantID
		item.SalesId = v.SalesID
		item.RobotName = v.RobotName
		item.OutTradeNo = v.OutTradeNo
		item.ChildOutTradeNo = v.ChildOutTradeNo
		item.OrderStatus = int32(v.OrderStatus)
		item.End = int32(v.End)
		item.PaymentId = int32(v.PaymentID)
		item.EndOutTradeNo = v.EndOutTradeNo
		item.PaymentAmount = float32(v.PaymentAmount)
		item.DiscountAmount = float32(v.DiscountAmount)
		item.Remarks = v.Remarks
		item.CreatedAt = v.CreatedAt
		item.UpdatedAt = v.UpdatedAt
		res.Data.List = append(res.Data.List, item)
	}
	return res, nil
}

// GoodsClick 商品点击量
func (s SaleAdminService) GoodsClick(ctx context.Context, req *sale_adminc.GoodsClickReq) (*sale_adminc.GoodsClickRsp, error) {
	res := &sale_adminc.GoodsClickRsp{}
	db := mysql.NewDB()
	//商品点击量
	var GoodsClickList []struct {
		GoodsID  string `json:"goods_id"`
		ClickNum int    `json:"click_num"`
	}
	tx := db.Model(&models.MaGoodsClick{})
	if req.RobotIds != "" {
		tx.Where("robot_name in ?", strings.Split(req.RobotIds, ","))
	}
	if req.StartTime != 0 && req.EndTime != 0 {
		tx.Where("new_start_time between ? and ?", req.StartTime, req.EndTime)
	}
	tx.Group("goods_id").Order("goods_id asc").
		Select("goods_id, sum(click_num) as click_num").
		Find(&GoodsClickList)
	var GoodsIDLsit []string
	for _, v := range GoodsClickList {
		GoodsIDLsit = append(GoodsIDLsit, v.GoodsID)
	}
	var GoodsList []models.MaGoodsInfo
	db.Model(&models.MaGoodsInfo{}).
		Where("goods_id in (?)", GoodsIDLsit).
		Select("goods_id,goods_name1").
		Find(&GoodsList)
	var GoodsIDNameMap = make(map[string]string)
	for _, v := range GoodsList {
		GoodsIDNameMap[v.GoodsID] = v.GoodsName1
	}
	for _, v := range GoodsClickList {
		var item = &sale_adminc.GoodsClickRsp_Data{}
		item.GoodsId = v.GoodsID
		if _, ok := GoodsIDNameMap[v.GoodsID]; ok {
			item.GoodsName = GoodsIDNameMap[v.GoodsID]
		}
		item.Click = int64(v.ClickNum)
		res.Data = append(res.Data, item)
	}
	return res, nil
}

// RobotExposure 商品曝光量
func (s SaleAdminService) RobotExposure(ctx context.Context, req *sale_adminc.RobotExposureReq) (*sale_adminc.RobotExposureRsp, error) {
	res := &sale_adminc.RobotExposureRsp{}
	startTime := carbon.CreateFromTimestamp(req.StartTime).ToDateTimeString()
	endTime := carbon.CreateFromTimestamp(req.EndTime).ToDateTimeString()
	FaceCountList, _ := dao.FaceCount{}.GetFaceCountList(ctx, dal.Q, strings.Split(req.MerchantId, ","),
		req.RobotIds, startTime, endTime, 0, 3, 0, 0)
	for _, v := range FaceCountList {
		item := &sale_adminc.RobotExposureRsp_Data{}
		item.RobotId = v.RobotName
		item.Exposure = int64(v.FaceCount)
		item.ExposureFront = int64(v.FaceCount0)
		item.ExposureLeft = int64(v.FaceCount1)
		item.ExposureRight = int64(v.FaceCount2)
		item.ExposureBack = int64(v.FaceCount3)
		res.Data = append(res.Data, item)
	}
	return res, nil
}

// 机器商品重置
func (s SaleAdminService) RobotGoodsReset(ctx context.Context, req *sale_adminc.RobotGoodsResetReq) (*sale_adminc.RobotGoodsResetRsp, error) {
	res := &sale_adminc.RobotGoodsResetRsp{}
	if req.RobotId == "" {
		res.Code = -1
		res.Msg = "机器ID不能为空"
		return res, nil
	}
	// 重置机器的货道状态
	_, err := robot.RobotService{}.ResetContainerStauts(mysql.NewDB(), req.RobotId, 0)
	if err != nil {
		res.Code = -1
		res.Msg = "机器重置商品错误"
		return res, nil
	}
	return res, nil
}

// 商品分类
func (s SaleAdminService) GoodsClass(ctx context.Context, req *sale_adminc.GoodsClassReq) (*sale_adminc.GoodsClassRsp, error) {
	res := &sale_adminc.GoodsClassRsp{}
	list, _, _ := dao.GoodsClass{}.List(ctx, dal.Q, "", "", int(req.Page), int(req.Limit))
	for _, v := range list {
		item := &sale_adminc.GoodsClassRsp_Data{
			Id:   v.ClassID,
			Name: v.ClassName,
		}
		res.Data = append(res.Data, item)
	}
	return res, nil
}

func (s SaleAdminService) CreateOrder(ctx context.Context, req *sale_adminc.CreateOrderReq) (*sale_adminc.CreateOrderRsp, error) {
	if len(req.List) <= 0 {
		return nil, errors.New("商品列表不能为空")
	}
	var robotGoodsData = make(map[string][]struct {
		OutTradeNo string
		RobotID    string
		ExpiredAt  int64
		MerchantID string
		GoodsData  schema.OrderGoodsDetail
	})
	var robotInfoMap = make(map[string]*models.MaRobot)
	for _, v := range req.List {
		robotDetail, _ := dao.Robot{}.Detail(ctx, dal.Q, v.RobotId, "")
		if robotDetail == nil {
			return nil, errors.New("机器不存在")
		}
		robotInfoMap[v.RobotId] = robotDetail
		GoodsData := schema.OrderGoodsDetail{
			GoodsName:       v.GoodsName,
			Univalent:       decimal.NewFromInt(v.Univalent).Div(decimal.NewFromInt(100)).InexactFloat64(),
			GoodsID:         v.GoodsId,
			ChildOutTradeNo: v.ChildOutTradeNo,
		}
		robotGoodsData[robotDetail.SalesID] = append(robotGoodsData[robotDetail.SalesID],
			struct {
				OutTradeNo string
				RobotID    string
				ExpiredAt  int64
				MerchantID string
				GoodsData  schema.OrderGoodsDetail
			}{
				OutTradeNo: v.OutTradeNo,
				RobotID:    v.RobotId,
				ExpiredAt:  v.ExpiredAt,
				MerchantID: robotDetail.MerchantID,
				GoodsData:  GoodsData,
			})
	}
	res := &sale_adminc.CreateOrderRsp{}
	for salesID, robotGoodsList := range robotGoodsData {
		var GoodsData []schema.OrderGoodsDetail
		var payAmount float64
		// 线下取货的，处理库存逻辑
		for _, goods := range robotGoodsList {
			// 订单是否存在
			var OrderInfo models.MaOrder
			mysql.NewDB().Model(&models.MaOrder{}).
				Where("out_trade_no = ?", goods.OutTradeNo).
				Where("child_out_trade_no = ?", goods.GoodsData.ChildOutTradeNo).
				Where("order_source = 1").
				Take(&OrderInfo)
			if OrderInfo.OutTradeNo != "" { // 已取货的修改状态，重新取货
				mysql.NewDB().Model(&models.MaOrder{}).
					Where("out_trade_no = ?", goods.OutTradeNo).
					Where("child_out_trade_no = ?", goods.GoodsData.ChildOutTradeNo).
					Updates(map[string]interface{}{
						"robot_name":   goods.RobotID,
						"sales_id":     salesID,
						"order_status": 2,
						"payment_id":   16,
						"end":          0,
						"areas1":       robotInfoMap[goods.RobotID].Areas1,
						"areas2":       robotInfoMap[goods.RobotID].Areas2,
						"areas3":       robotInfoMap[goods.RobotID].Areas3,
						"areas4":       robotInfoMap[goods.RobotID].Areas4,
						"areas5":       robotInfoMap[goods.RobotID].Areas5,
						"remarks":      "",
						"coupon_code":  "",
						"expired_at":   goods.ExpiredAt,
					})
				if OrderInfo.End == 0 {
					var CountData []schema.OrderGoodsDetailOld
					json.Unmarshal([]byte(OrderInfo.CountData), &CountData)
					// 冻结库存-1
					mysql.NewDB().Model(&models.MaRobotSalesInfo{}).
						Where("sales_id = ?", salesID).
						Where("goods_id = ?", goods.GoodsData.GoodsID).
						Where("container_num = ?", CountData[0].ContainerNum).
						Where("goods_reserve_inventory > 0").
						UpdateColumn("goods_reserve_inventory", gorm.Expr("goods_reserve_inventory - 1"))
				}
				robotContainers, _ := dao.RobotSalesInfo{}.List(ctx, dal.Q, goods.RobotID, goods.GoodsData.GoodsID, 1, 1)
				if len(robotContainers) == 0 {
					res.Code = -1
					res.Msg = "机器商品没有设置或商品存货为空"
					return res, nil
				}
				// 未指定货道
				maxRestInventory := 0
				for _, robotV := range robotContainers {
					if (robotV.GoodsInventory - robotV.GoodsReserveInventory) >= maxRestInventory { // 选库存数量最多的货道
						maxRestInventory = robotV.GoodsInventory - robotV.GoodsReserveInventory
						goods.GoodsData.ContainerNum = strconv.Itoa(robotV.ContainerNum)
					}
				}
				// 冻结库存+1
				UpdateRows := mysql.NewDB().Model(&models.MaRobotSalesInfo{}).
					Where("sales_id = ?", salesID).
					Where("goods_id = ?", goods.GoodsData.GoodsID).
					Where("container_num = ?", goods.GoodsData.ContainerNum).
					Where("(goods_inventory - goods_reserve_inventory) > 0"). // 可用库存 > 0
					UpdateColumn("goods_reserve_inventory", gorm.Expr("goods_reserve_inventory + 1")).
					RowsAffected
				if UpdateRows <= 0 {
					res.Code = -1
					res.Msg = "机器商品没有设置或商品存货为空"
					return res, nil
				}
			} else { // 未取货的创单并取码
				payAmount += goods.GoodsData.Univalent
				GoodsData = append(GoodsData, goods.GoodsData)
			}
		}

		if len(GoodsData) > 0 {
			// 创单
			_, err := robot.RobotService{}.CreateOrderPluralGoodsMore(
				ctx, mysql.NewDB(), req.RemoteIp, salesID, payAmount, GoodsData,
				9, 0, robotGoodsList[0].OutTradeNo, "", "", 1, robotGoodsList[0].ExpiredAt,
			)
			logx.Info(context.Background(), "create order rpc: 创建订单", logx.Err(err))
			if err != nil {
				res.Code = -1
				res.Msg = err.Error()
				return res, nil
			}
			// 订单状态改为已支付，支付方式为小程序支付
			if req.UserAddress == nil {
				logx.Info(context.Background(), "create order rpc: 订单状态已支付")
				mysql.NewDB().Model(&models.MaOrder{}).
					Where("out_trade_no = ?", robotGoodsList[0].OutTradeNo).
					Updates(map[string]interface{}{
						"order_status": 2, // 已支付
						"payment_id":   16,
					})
			} else {
				logx.Info(context.Background(), "create order rpc: 订单状态待发货")
				// 更新订单状态为待发货
				mysql.NewDB().Model(&models.MaOrder{}).
					Where("out_trade_no = ?", robotGoodsList[0].OutTradeNo).
					Updates(map[string]interface{}{
						"order_status": define.OrderStatus_Shipment_Pending, // 待发货
						"payment_id":   16,
					})
				// 订单收货地址信息
				dao.OrderUserAddress{}.Create(ctx, mysql.NewDB(), models.OrderShipmentInfo{
					OutTradeNo:    req.List[0].OutTradeNo,
					ExpressFee:    *req.ExpressFee,
					UserName:      req.UserAddress.UserName,
					TelNumber:     req.UserAddress.TelNumber,
					PostalCode:    req.UserAddress.PostalCode,
					ProvinceName:  req.UserAddress.ProvinceName,
					CityName:      req.UserAddress.CityName,
					CountyName:    req.UserAddress.CountyName,
					StreetName:    req.UserAddress.StreetName,
					DetailAddress: req.UserAddress.DetailAddress,
				})
			}
		}

		// 线下取货的，处理取货码
		if req.UserAddress == nil {
			logx.Info(context.Background(), "create order rpc: 生成取货码")
			// 获取取货码
			codes, _ := coupon.CouponCode{}.GetCode(ctx, robotGoodsList[0].MerchantID, "0", len(GoodsData),
				robotGoodsList[0].ExpiredAt, robotGoodsList[0].OutTradeNo)
			res.Code = 0
			res.Data = append(res.Data, &sale_adminc.CreateOrderRsp_Data{
				OutTradeNo: robotGoodsList[0].OutTradeNo,
				Codes:      codes[0],
			})
			// 核销锁定，消费一个子码
			err := coupon.CouponCode{}.ConsumeLock(ctx, codes[0], robotGoodsList[0].OutTradeNo, time.Hour*1)
			if err != nil {
				logx.Error(context.Background(), "grpc code consume lock error")
			}
		}
	}
	return res, nil
}
func (s SaleAdminService) GetCartGoods(ctx context.Context, req *sale_adminc.GetCartGoodsReq) (*sale_adminc.GetCartGoodsRsp, error) {
	res := &sale_adminc.GetCartGoodsRsp{}
	totalAmount, CartGoods, err := service.OrderPoints{}.GetCartGoods(ctx, req.OrderId)
	if err != nil {
		res.Code = -1
		res.Msg = err.Error()
		return res, nil
	}
	res.Code = 0
	res.Msg = ""
	res.TotalAmount = decimal.NewFromFloat(totalAmount).Mul(decimal.NewFromInt(100)).IntPart() // 分
	for _, v := range CartGoods {
		item := &sale_adminc.GetCartGoodsRsp_List{
			Id:             v.ID,
			ClassId:        v.ClassID,
			GoodsName:      v.GoodsName,
			ContainerNum:   v.ContainerNum,
			Univalent:      decimal.NewFromFloat(v.Univalent).Mul(decimal.NewFromInt(100)).IntPart(), // 分
			GoodsId:        v.GoodsID,
			GoodsType:      int64(v.GoodsType),
			GoodsImage:     v.GoodsImage,
			Points:         float32(v.Points),
			PointsSupport:  int64(v.PointsSupport),
			DeductionLimit: float32(v.DeductionLimit),
			RobotName:      v.RobotName,
		}
		res.List = append(res.List, item)
	}
	return res, nil
}
func (s SaleAdminService) WechatJSPay(ctx context.Context, req *sale_adminc.WechatJSPayReq) (*sale_adminc.WechatJSPayRsp, error) {
	res := &sale_adminc.WechatJSPayRsp{}
	dataReturn, err := service.OrderPoints{}.WechatJspay(ctx, req.OrderId, req.Openid, float64(req.Points), int(req.Wapp))
	if err != nil {
		res.Code = -1
		res.Msg = err.Error()
		return res, nil
	}
	res.Code = 0
	res.Msg = ""
	res.Data = &sale_adminc.WechatJSPayRsp_Data{
		AppId:     dataReturn.AppId,
		TimeStamp: dataReturn.TimeStamp,
		NonceStr:  dataReturn.NonceStr,
		Package:   dataReturn.Package,
		PaySign:   dataReturn.PaySign,
	}
	return res, nil
}

func (s SaleAdminService) OrderDetail(ctx context.Context, req *sale_adminc.OrderDetailReq) (*sale_adminc.OrderDetailRsp, error) {
	res := &sale_adminc.OrderDetailRsp{}

	if strings.Contains(req.OutTradeNo, "P") {
		req.OutTradeNo = strings.TrimSuffix(req.OutTradeNo, "P")
	} else if strings.Contains(req.OutTradeNo, "F") {
		req.OutTradeNo = strings.Split(req.OutTradeNo, "F")[0]
	}
	orderInfo, _ := dao.NewOrder(ctx, dal.Q).WithOutTradeNoCond(req.OutTradeNo).OrderDetail()
	info := &sale_adminc.OrderDetailRsp_Data{}
	if orderInfo != nil {
		goodsInfo, _ := dao.Goods{}.Detail(ctx, dal.Q, orderInfo.GoodsID)
		info.OutTradeNo = orderInfo.OutTradeNo
		info.ChildOutTradeNo = orderInfo.ChildOutTradeNo
		info.RobotId = orderInfo.RobotName
		info.OrderStatus = int32(orderInfo.OrderStatus)
		info.GoodsId = orderInfo.GoodsID
		info.GoodsName = goodsInfo.GoodsName1
		info.GoodsType = int32(goodsInfo.GoodsType)
		info.Univalent = decimal.NewFromFloat(orderInfo.ActualAmount).Mul(decimal.NewFromInt(100)).IntPart()
		info.CreatedAt = orderInfo.CreatedAt
		info.UpdatedAt = orderInfo.UpdatedAt
	}
	res.Data = info
	return res, nil
}

func (s SaleAdminService) CheckCode(ctx context.Context, req *sale_adminc.CheckCodeReq) (*sale_adminc.CheckCodeRsp, error) {
	res := &sale_adminc.CheckCodeRsp{}
	_, _, _, _, _, err := coupon.CouponCode{}.Check(ctx, req.SalesId, float64(req.OrderAmount), req.Code, int(req.UseCase), 1)
	if err != nil {
		res.Code = -1
		res.Msg = err.Error()
		return res, nil
	}
	res.Code = 0
	res.Msg = ""
	return res, nil
}

// AllGoodsList 商品列表
func (s SaleAdminService) AllGoodsList(ctx context.Context, req *sale_adminc.AllGoodsListReq) (*sale_adminc.AllGoodsListRsp, error) {
	res := &sale_adminc.AllGoodsListRsp{}
	res.Data = &sale_adminc.AllGoodsListRsp_Data{}
	db := mysql.NewDB()
	var goodsList = []models.MaGoodsInfo{}
	db.Model(&models.MaGoodsInfo{}).
		Where("deleted = 0").
		Find(&goodsList)
	for _, v := range goodsList {
		item := &sale_adminc.AllGoodsListRsp_List{
			GoodsId:          v.GoodsID,
			GoodsName:        v.GoodsName1,
			Price:            decimal.NewFromFloat(v.Price).Mul(decimal.NewFromInt(100)).IntPart(),
			GoodsDescription: v.GoodsDescription1,
			GoodsImage:       v.GoodsImage,
			GoodsStatus:      int32(v.GoodsStatus),
			TotalSales:       int64(v.TotalSales),
			GoodsCode:        v.GoodsCode,
			UseRc:            int32(v.UseRC),
			CodeImage:        v.CodeImage,
			IsAuth:           int32(v.IsAuth),
			UnderlinePrice:   decimal.NewFromFloat(v.Price1).Mul(decimal.NewFromInt(100)).IntPart(),
			GoodsDetail:      v.GoodsDetail,
			GoodsVoice:       v.GoodsVoice,
			ShowTag:          v.ShowTag,
			GoodsType:        int32(v.GoodsType),
			Points:           float32(v.Points),
			PointsSupport:    int32(v.PointsSupport),
		}
		res.Data.List = append(res.Data.List, item)
	}
	return res, nil
}

// GoodsStock 商品库存
func (s SaleAdminService) GoodsUsableStock(ctx context.Context, req *sale_adminc.GoodsUsableStockReq) (*sale_adminc.GoodsUsableStockRsp, error) {
	db := mysql.NewDB()
	res := &sale_adminc.GoodsUsableStockRsp{}
	// 获取salesID
	robotIDs := []string{}
	salesIDs := []string{}
	if req.RobotId != "" {
		robotIDs = strings.Split(req.RobotId, ",")
	}
	for _, robotID := range robotIDs {
		RobotInfo, _ := dao.Robot{}.RobotDetail(ctx, db, req.MerchantId, robotID, "")
		if RobotInfo == nil || RobotInfo.ID == "" {
			continue
		}
		salesIDs = append(salesIDs, RobotInfo.SalesID)
	}

	// 机器货物信息
	SalesInfoList := []models.MaRobotSalesInfo{}
	tx := db.Model(&models.MaRobotSalesInfo{})
	// 如果salesIDs为空，则获取该商户的全部设备
	if len(salesIDs) <= 0 {
		cli, err := client.GetDeviceAdminClient()
		if err != nil {
			return res, nil
		}
		rsp, err := cli.DeviceList(ctx, &devicec.DeviceListReq{
			MerchantId: req.MerchantId,
		})
		if err != nil || rsp == nil {
			return res, nil
		}
		for _, record := range rsp.List {
			salesIDs = append(salesIDs, record.IdentificationCode)
		}
	}
	// 获取售卖信息
	tx.Where("sales_id IN ?", salesIDs).
		Where("container_status = 1").
		Where("container_use_status = 1").
		Find(&SalesInfoList)
	GoodsIDList := []string{}
	for _, v := range SalesInfoList {
		if !lo.Contains(GoodsIDList, v.GoodsID) {
			GoodsIDList = append(GoodsIDList, v.GoodsID)
		}
	}
	// 商品名称信息
	GoodsList := []models.MaGoodsInfo{}
	db.Model(&models.MaGoodsInfo{}).
		Where("goods_id in (?)", GoodsIDList).
		Select("goods_id,goods_name1").
		Find(&GoodsList)
	GoodsIDNameMap := make(map[string]string)
	for _, v := range GoodsList {
		GoodsIDNameMap[v.GoodsID] = v.GoodsName1
	}
	list := []*sale_adminc.GoodsUsableStockRsp_List{}
	for _, v := range SalesInfoList {
		item := &sale_adminc.GoodsUsableStockRsp_List{}
		item.GoodsId = v.GoodsID
		if _, ok := GoodsIDNameMap[v.GoodsID]; ok {
			item.GoodsName = GoodsIDNameMap[v.GoodsID]
		}
		item.ContainerNum = int64(v.ContainerNum)
		item.Stock = int64(v.GoodsInventory - v.GoodsReserveInventory)
		list = append(list, item)
	}
	res.Code = 0
	res.Msg = ""
	res.Data = list
	return res, nil
}

func (s SaleAdminService) GetWanXiangMember(ctx context.Context, req *sale_adminc.GetWanXiangMemberReq) (*sale_adminc.GetWanXiangMemberRsp, error) {
	res := &sale_adminc.GetWanXiangMemberRsp{}
	data, err := points.NewPoints("5").GetMemberInfo(ctx, mysql.NewDB(), "", "", req.Openid)
	if err != nil {
		res.Code = 100099
		res.Msg = "当前用户未注册"
		return res, nil
	}
	res.Data = &sale_adminc.GetWanXiangMemberRsp_Data{
		NickName: data.NickName,
		Points:   float32(data.Points),
		HeadImg:  data.HeadImg,
		Phone:    data.Phone,
		Id:       data.ID,
		CardNo:   data.CardNo,
	}
	return res, nil
}

func (s SaleAdminService) GetWanXiangPoints(ctx context.Context, req *sale_adminc.GetWanXiangPointsReq) (*sale_adminc.GetWanXiangMemberRsp, error) {
	res := &sale_adminc.GetWanXiangMemberRsp{}
	data, err := points.NewPoints("5").PointsQuery(ctx, "", req.Openid, req.Mallcode)
	if err != nil {
		res.Code = 100099
		res.Msg = "当前用户未注册"
		return res, nil
	}
	res.Data = &sale_adminc.GetWanXiangMemberRsp_Data{
		NickName: "",
		Points:   float32(data),
		HeadImg:  "",
		Phone:    "",
		Id:       "",
		CardNo:   "",
	}
	return res, nil
}

func (s SaleAdminService) PointsConsume(ctx context.Context, req *sale_adminc.PointsConsumeReq) (*sale_adminc.PointsConsumeRsp, error) {
	res := &sale_adminc.PointsConsumeRsp{}
	tradeErr := points.NewPoints(req.PointsId).PointsConsume(ctx, mysql.NewDB(), "", req.Openid, req.Orderid, float64(req.Points), req.Mallcode)
	if tradeErr != nil {
		res.Code = -1
		res.Msg = "扣积分失败"
		return res, nil
	}
	res.Code = 0
	res.Msg = "扣积分成功"
	return res, nil

}

func (s SaleAdminService) CheckOrder(ctx context.Context, req *sale_adminc.CheckOrderReq) (*sale_adminc.CheckOrderRsp, error) {
	res := &sale_adminc.CheckOrderRsp{}

	logx.Error(ctx, "CheckOrder SaleAdminService", logx.Any("req.Orderid", req.Orderid))
	_, err := service.OrderPoints{}.CheckOrder(ctx, req.Orderid, req.Openid, float64(req.Points))
	if err != nil {
		res.Code = -1
		res.Msg = err.Error()
		return res, nil
	}
	res.Code = 0
	res.Msg = "扣积分成功"

	return res, nil
}

func (s SaleAdminService) PointsReverse(ctx context.Context, req *sale_adminc.PointsReverseReq) (*sale_adminc.PointsReverseRsp, error) {

	logx.Info(context.Background(), "PointsReverse SaleAdminService", logx.Any("Start", ""))

	res := &sale_adminc.PointsReverseRsp{}
	tradeErr := points.NewPoints(req.PointsId).PointsReverse(ctx, mysql.NewDB(), "", req.Openid, "", req.Orderid, float64(req.Points), req.Mallcode)
	if tradeErr != nil {
		res.Code = -1
		res.Msg = "回退积分失败"
		return res, nil
	}
	res.Code = 0
	res.Msg = "回退积分成功"
	return res, nil
}

func (s SaleAdminService) DailyReport(ctx context.Context, req *sale_adminc.DailyReportReq) (*sale_adminc.DailyReportRsp, error) {
	res := &sale_adminc.DailyReportRsp{}

	list, total, summary, err := service.RobotDailyReport{}.DailyReport(ctx,
		req.LoginMerchantId,
		req.StartTime,
		req.EndTime,
		req.MerchantIds,
		req.RobotId,
		req.LocationId,
		req.CityId,
		req.DistrictId,
		int(req.GroupType),
		int(req.DataType),
		req.OrderType,
		int(req.SummaryType),
		int(req.Page),
		int(req.Limit))

	if err != nil {
		res.Code = -1
		res.Msg = err.Error()
		return res, nil
	}

	// Convert list to proto DailyReport format
	var protoList []*sale_adminc.RobotDailyReport
	for _, item := range list {
		protoReport := &sale_adminc.RobotDailyReport{
			Id:                      item.ID,
			MerchantId:              *item.MerchantID,
			MerchantName:            *item.MerchantName,
			RobotName:               *item.RobotName,
			CreatedDate:             item.CreatedDate.Unix(),
			CreatedDateFormated:     *item.CreatedDateFormated,
			ProvinceId:              *item.ProvinceID,
			CityId:                  *item.CityID,
			DistrictId:              *item.DistrictID,
			LocationId:              *item.LocationID,
			Province:                *item.Province,
			City:                    *item.City,
			District:                *item.District,
			Location:                *item.Location,
			GoodsInventory:          *item.GoodsInventory,
			GoodsMaxInventory:       *item.GoodsMaxInventory,
			Gmv:                     *item.GMV,
			PaymentAmount:           *item.PaymentAmount,
			TransactionAmount:       *item.TransactionAmount,
			DiscountAmount:          *item.DiscountAmount,
			RefundAmount:            *item.RefundAmount,
			GiveAmount:              *item.GiveAmount,
			TotalOrder:              *item.TotalOrder,
			TotalPaidOrder:          *item.TotalPaidOrder,
			TotalNotPaidOrder:       *item.TotalNotPaidOrder,
			TotalRefundOrder:        *item.TotalRefundOrder,
			TotalPaidUser:           *item.TotalPaidUser,
			TotalScreenClick:        *item.TotalScreenClick,
			TotalGoodsClick:         *item.TotalGoodsClick,
			Facecount:               *item.Facecount,
			FacecountFront:          *item.FacecountFront,
			FacecountLeft:           *item.FacecountLeft,
			FacecountRight:          *item.FacecountRight,
			FacecountBack:           *item.FacecountBack,
			Starecount:              *item.Starecount,
			StarecountFront:         *item.StarecountFront,
			StarecountLeft:          *item.StarecountLeft,
			StarecountRight:         *item.StarecountRight,
			StarecountBack:          *item.StarecountBack,
			TotalOperationDuration:  *item.TotalOperationDuration,
			TotalChargingDuration:   *item.TotalChargingDuration,
			TotalIdleDuration:       *item.TotalIdleDuration,
			TotalTaskDuration:       *item.TotalTaskDuration,
			TotalToTaskDuration:     *item.TotalToTaskDuration,
			TotalToChargingDuration: *item.TotalToChargingDuration,
			TotalFaultDuration:      *item.TotalFaultDuration,
			TotalTaskOdometer:       *item.TotalTaskOdometer,
			TotalTaskRunCount:       *item.TotalTaskRunCount,
			OpeningFlag:             *item.OpeningFlag,
			OpeningTime:             *item.OpeningTime,
			RobotCount:              *item.RobotCount,
			GoodsClickRatio:         *item.GoodsClickRatio,
			PaidRatio:               *item.PaidRatio,
			CreateOrderRatio:        *item.CreateOrderRatio,
			RefundRatio:             *item.RefundRatio,
			CreatedAt:               item.CreatedAt,
			UpdatedAt:               item.UpdatedAt,
		}
		protoList = append(protoList, protoReport)
	}

	if summary != nil {
		res.Summary = &sale_adminc.RobotDailyReport{
			Id:                      summary.ID,
			MerchantId:              *summary.MerchantID,
			MerchantName:            *summary.MerchantName,
			RobotName:               *summary.RobotName,
			CreatedDate:             summary.CreatedDate.Unix(),
			CreatedDateFormated:     *summary.CreatedDateFormated,
			ProvinceId:              *summary.ProvinceID,
			CityId:                  *summary.CityID,
			DistrictId:              *summary.DistrictID,
			LocationId:              *summary.LocationID,
			Province:                *summary.Province,
			City:                    *summary.City,
			District:                *summary.District,
			Location:                *summary.Location,
			GoodsInventory:          *summary.GoodsInventory,
			GoodsMaxInventory:       *summary.GoodsMaxInventory,
			Gmv:                     *summary.GMV,
			PaymentAmount:           *summary.PaymentAmount,
			TransactionAmount:       *summary.TransactionAmount,
			DiscountAmount:          *summary.DiscountAmount,
			RefundAmount:            *summary.RefundAmount,
			GiveAmount:              *summary.GiveAmount,
			TotalOrder:              *summary.TotalOrder,
			TotalPaidOrder:          *summary.TotalPaidOrder,
			TotalNotPaidOrder:       *summary.TotalNotPaidOrder,
			TotalRefundOrder:        *summary.TotalRefundOrder,
			TotalPaidUser:           *summary.TotalPaidUser,
			TotalScreenClick:        *summary.TotalScreenClick,
			TotalGoodsClick:         *summary.TotalGoodsClick,
			Facecount:               *summary.Facecount,
			FacecountFront:          *summary.FacecountFront,
			FacecountLeft:           *summary.FacecountLeft,
			FacecountRight:          *summary.FacecountRight,
			FacecountBack:           *summary.FacecountBack,
			Starecount:              *summary.Starecount,
			StarecountFront:         *summary.StarecountFront,
			StarecountLeft:          *summary.StarecountLeft,
			StarecountRight:         *summary.StarecountRight,
			StarecountBack:          *summary.StarecountBack,
			TotalOperationDuration:  *summary.TotalOperationDuration,
			TotalChargingDuration:   *summary.TotalChargingDuration,
			TotalIdleDuration:       *summary.TotalIdleDuration,
			TotalTaskDuration:       *summary.TotalTaskDuration,
			TotalToTaskDuration:     *summary.TotalToTaskDuration,
			TotalToChargingDuration: *summary.TotalToChargingDuration,
			TotalFaultDuration:      *summary.TotalFaultDuration,
			TotalTaskOdometer:       *summary.TotalTaskOdometer,
			TotalTaskRunCount:       *summary.TotalTaskRunCount,
			OpeningFlag:             *summary.OpeningFlag,
			OpeningTime:             *summary.OpeningTime,
			RobotCount:              *summary.RobotCount,
			GoodsClickRatio:         *summary.GoodsClickRatio,
			PaidRatio:               *summary.PaidRatio,
			CreateOrderRatio:        *summary.CreateOrderRatio,
			RefundRatio:             *summary.RefundRatio,
			CreatedAt:               summary.CreatedAt,
			UpdatedAt:               summary.UpdatedAt,
		}
	}

	res.Code = 0
	res.Total = total
	res.List = protoList

	return res, nil
}
